import { convertToObject } from "typescript";

export function loadImage(url: string, onSuccess: Function) {
    const img = new Image();
    //异步过程
    img.src = url;
    img.onload = function () {
        onSuccess(img);
    }
}

export const store: any = {};

export function getImage(url: string) {
    return store[url];
}

export function loadMultiImage(list: string[], onSuccess: Function) {
    let count = 0;
    for (const url of list) {
        loadImage(url, function onLoadItem(img) {
            count++;
            store[url] = img;
            if (count === list.length) {
                onSuccess();
            }
        })
    }
}

//抽象类 绘制个体
export abstract class RenderObject {
    x=0;
    y=0;
    alpha=1; //xy坐标 ，alpha透明度

    draw(context:CanvasRenderingContext2D){
        context.globalAlpha = this.alpha;
        this.render(context);
    }

    abstract render(context:CanvasRenderingContext2D):void;
} //从该抽象类出发定义各个详细种类

export class BitmapObj extends RenderObject{ //位图对象
    source:string; //图片地址
    render(context: CanvasRenderingContext2D): void {
        const img = getImage(this.source);
        if(img){
            context.drawImage(img,this.x,this.y);
        }
    }
    
}

export class RectObj extends RenderObject{ //矩形对象
    color = '#000000';
    width = 100;
    height = 100;
    render(context: CanvasRenderingContext2D): void {
        context.save();
        context.fillStyle = this.color;
        context.fillRect(this.x,this.y,this.width,this.height);
        context.restore();
    }
}

export class TextObj extends RenderObject{ //文字对象
    color = '#000000';
    font = '10px 宋体';
    text = '';

    render(context:CanvasRenderingContext2D):void{
        context.save();
        context.fillStyle = this.color;
        context.font = this.font;
        context.fillText(this.text,this.x,this.y+20);
        context.restore();
    }
}


export class mycanv{
    canvas:HTMLCanvasElement;
    context:CanvasRenderingContext2D;
    //构造函数 参数：元素ID
    constructor(ElID:string) {
        this.canvas = document.getElementById(ElID) as HTMLCanvasElement;
        this.context = this.canvas.getContext('2d');
    }

    //绘制图像文件 参数：文件路径，坐标x, 坐标y
    public drawimg(address:string,x:number,y:number) {
        const IMG = getImage(address);
        this.context.drawImage(IMG,x,y);
    }

    //绘制矩形 参数：颜色，宽，高，坐标x，坐标y
    public fillrec(color:string,len:number,heigh:number,x:number,y:number){
        this.context.fillStyle = color;
        this.context.fillRect(x,y,len,heigh);
        this.context.fillStyle='white';
    }

    //绘制文字 参数：颜色，字体，内容，坐标x，坐标y
    public filltext(color:string,font:string,text:string,x:number,y:number){
        this.context.fillStyle = color;
        this.context.font = font;
        this.context.fillText(text,x,y);
        this.context.fillStyle='white';
    }
}

export class GameEngine{
    objects:{[id:string]:RenderObject}={};

    private renderObj:RenderObject[] = [];

    onStart?:()=>void;
    onUpdate?:(duringTime:number)=>void;
    onTick?:()=>void;

    start(images:string[],sceneConfig:any,onComplete?:Function){
        const initialTime =Date.now();
        loadMultiImage(images,()=>{
            this.loadScene(sceneConfig);
    
            if(this.onStart){
                this.onStart();
            }
            const advancedTime =Date.now() - initialTime;
            this.enterFrame(advancedTime);

            if(onComplete){
                onComplete;
            }
        })
    }
    private lastTime = 0;

    enterFrame(advancedTime:number){
        const duringTime = advancedTime - this.lastTime;
        this.lastTime = advancedTime;
        this.onEnterFrame(duringTime);
        requestAnimationFrame((advancedTime)=>this.enterFrame(advancedTime));
    }
 
    private iterationCurrentTime = 0;

    private onEnterFrame(duringTime:number){
        const canvas = document.getElementById('gameCanvas') as HTMLCanvasElement;
        const context = canvas.getContext('2d');
        context.clearRect(0,0,canvas.width,canvas.height);
        this.iterationCurrentTime +=duringTime;
        const fps =60;
        const mileSecondPerTick = 1000/fps;
        while(this.iterationCurrentTime>=mileSecondPerTick){
            this.iterationCurrentTime -= mileSecondPerTick;
            if(this.onTick){
                this.onTick();
            }
        }
        if(this.onUpdate){
            this.onUpdate(duringTime);
        }
        this.draw(context);
    }

    getRenderObj(id: string){
        return this.objects[id];
    }

    addRenderObj(renderObject:RenderObject){
        this.renderObj.push(renderObject);
    }

    draw(context:CanvasRenderingContext2D){
        for(const renderObject of this.renderObj){
            renderObject.draw(context);
        }
    }
    
    loadScene(sceneConfig:any){
        for(let config of sceneConfig){
            const object = createRenderObject(config.type,config.properties);
            if(config.id){
                this.objects[config.id]=object;
            }
            this.addRenderObj(object);
        }
    }

}

function createRenderObject(type:string,properties:any):RenderObject {
    let renderObj:RenderObject;
    switch(type){
        case 'rectangle':
            const rect =new RectObj();
            rect.color = properties.color || '0x000000';
            rect.width = properties.width || 100;
            rect.height = properties.height || 100;
            renderObj=rect;
            break;
        case 'textfield':
            const text = new TextObj();
            text.color = properties.color || '0x000000';
            text.font = properties.font || '10px 宋体';
            text.text = properties.text || '';
            renderObj =text;
            break;
        case 'bitmap':
            const bitmap =new BitmapObj();
            bitmap.source = properties.source || '';
            renderObj = bitmap;
    }
    renderObj.x = properties.x || 0;
    renderObj.y = properties.y || 0;
    renderObj.alpha = properties.hasOwnProperty('alpha') ? properties.alpha:1;
    return renderObj;
    
}

export class Move{
    private initialX: number =0;
    constructor(private renderobj:RenderObject, private speed:number){
        this.initialX = renderobj.x;
    }

    update(duringTime:number){
        this.renderobj.x = this.initialX + this.speed * (duringTime /1000);
    }
}